import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Stack;

public class SemanticoCIL implements ISemantico {

    HashMap variaveis = new HashMap();
    Stack pilhaSe = new Stack();
    int contaSe = 0;
    String nomePrograma;
    StringBuffer sb = new StringBuffer();

    public void escreverArquivo() {
	try {
	    System.out.print("Codigo intermediario...");
	    BufferedWriter out = new BufferedWriter(new FileWriter(nomePrograma
		    + ".il"));
	    out.write(sb.toString());
	    out.close();
	    System.out.println("OK");
	} catch (IOException e) {
	    System.err.println("Erro ao tentar salvar em arquivo:"
		    + e.getMessage());
	}
    }

    public void compilaIL() {
	try {
	    System.out.print("Compilacao codigo IL...");
	    Runtime.getRuntime().exec("ilasm.bat " + nomePrograma + ".il");
	    System.out.println("OK");
	} catch (IOException e) {
	    e.printStackTrace();
	}
    }

    public void programaIni(String nomePrograma) {
	System.out.print("Parsing...");
	this.nomePrograma = nomePrograma;
	sb.append(".assembly " + nomePrograma + "{}\n");
	sb.append(".class " + nomePrograma);
	sb.append("{\n");
	sb.append("  .method static public void main() il managed\n");
	sb.append("  {\n");
	sb.append("    .entrypoint\n");
    }

    public void programaFim() {
	sb.append("    ret\n");
	sb.append("  }\n");
	sb.append("}\n");
	System.out.println("OK");
	escreverArquivo();
	compilaIL();
    }

    public void declaraVariavel(String str) {
	variaveis.put(str, new Integer(99));
	sb.append("    .locals(int32 " + str + ")\n");
    }

    public void atribuicao(String str, Object valor) {
	if (variaveis.containsKey(str)) {
	    variaveis.put(str, valor);
	    sb.append("    stloc " + str + "\n");
	} else {
	    System.err.println("erro: Variavel " + str + " nao declarada.");
	    System.exit(1);
	}
    }

    public void impressaoVariavel(String str) {
	if (variaveis.containsKey(str)) {
	    sb.append("    ldloc " + str + "\n");
	    sb
		    .append("    call void [mscorlib]System.Console::WriteLine(int32)\n");
	} else {
	    System.err.println("erro: Variavel " + str + " nao declarada.");
	    System.exit(1);
	}

    }

    public void impressaoValor() {
	sb.append("    call void [mscorlib]System.Console::WriteLine(int32)\n");
    }

    public void condicaoInicio(Boolean b) {
	contaSe++;
	pilhaSe.push(new Integer(contaSe));

	sb.append("    ldc.i4 " + (b ? 1 : 0) + "\n");
	sb.append("    brfalse senao" + contaSe + "\n");
    }

    public void condicaoEntao() {
	sb.append("    br fimif" + pilhaSe.peek() + "\n");
    }

    public void condicaoSenao() {
	sb.append("    senao" + pilhaSe.peek() + ":\n");
    }

    public void condicaoFim() {
	sb.append("    fimif" + pilhaSe.pop() + ":\n");
    }

    public void numero(Integer num) {
	sb.append("    ldc.i4 " + num + "\n");
    }

    public void somar() {
	sb.append("    add\n");
    }

    public void subtrair() {
	sb.append("    sub\n");
    }

    public void dividir() {
	sb.append("    div\n");
    }

    public void multiplicar() {
	sb.append("    mul\n");
    }

    public void impressaoValor(Object valor) {
	// TODO Auto-generated method stub
	// Feito pra eliminar os erros apenas...
    }

    public void atribuicao(String str) {
	// TODO Auto-generated method stub
	// Feito pra eliminar os erros apenas...

    }
}
